// 单点修改 + 区间查询 #include<iostream> #define rep(i, a, b) for(int i = (a); i <= (b); i ++ ) usingnamespace std; constint N = 100010; int n, m; int a[N], tr[N];
intlowbit(int x) { return x & -x; }
voidadd(int x, int v) { for(int i = x; i <= n; i += lowbit(i)) tr[i] += v; }
intquery(int x) { int ret = 0; for(int i = x; i > 0; i -= lowbit(i)) ret += tr[i]; return ret; }
signedmain() { cin >> n >> m; rep(i, 1, n) cin >> a[i]; rep(i, 1, n) add(i, a[i]); while(m -- ) { int op, x, y; cin >> op >> x >> y; if(op == 0) cout << query(y) - query(x - 1) << endl; elseadd(x, y); } return0; }
区间修改 + 单点查询
原来树状数组维护的是原数组a, query得到的结果的前缀和s, 整体过程是 a -> s. 那么 b->a 也有相同的积分关系, 也就是差分数组到原数组, 我们可以将add改为两个点的修改操作(b), query得到的结果是a, 这就是单点的值.
// 区间修改 + 单点查询 #include<iostream> #define rep(i, a, b) for(int i = (a); i <= (b); i ++) usingnamespace std; constint N = 100010; int n, m; int a[N]; int tr[N * 2];
intlowbit(int x) { return x & -x; }
voidadd(int x, int v) { for(int i = x; i < N; i += lowbit(i)) tr[i] += v; }
intquery(int x) { int res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; }
// 区间修改 + 区间查询 #include<iostream> #define rep(i, a, b) for(int i = (a); i <= (b); i ++ ) #define int long long usingnamespace std; constint N = 100010; int n, m; int a[N]; int tr1[N * 2], tr2[N * 2];
intlowbit(int x) { return x & -x; }
voidadd(int tr[], int x, int c)// 修改b { for(int i = x; i <= N; i += lowbit(i)) tr[i] += c; }
intquery(int tr[], int x)// 获取a { int res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; }
#include<iostream> #include<vector> #include<cstring> #include<algorithm> #include<stack> #define rep(i, a, b) for(int i = (a); i <= (b); i ++ ) usingnamespace std; constint N = 100010; // 求第k大元素(k可灵活) -> 树状数组 + 二分 int n; int tr[N * 2]; stack<int> st;
intlowbit(int x) { return x & -x; }
voidadd(int x, int v) { for(int i = x; i <= N; i += lowbit(i)) tr[i] += v; }
intquery(int x) { int res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; }
signedmain() { cin >> n; rep(i, 1, n) { string op; cin >> op; if(op == "Pop") { if(!st.size()) cout << "Invalid" << endl; else { cout << st.top() << endl; add(st.top(), -1); st.pop(); } } elseif(op == "PeekMedian") { if(!st.size()) cout << "Invalid" << endl; else { // 计算中值k int sz = st.size(); int k; if(sz & 1) k = (sz + 1) / 2; else k = sz / 2; // 二分答案, 找第k个元素的元素值 int l = 1, r = N; while(l < r) { int mid = l + r >> 1; if(query(mid) >= k) r = mid; else l = mid + 1; } cout << l << endl; } } else { int x; cin >> x; st.push(x); add(x, 1); } } return0; }
// 树状数组 + 二分 #include<iostream> #define rep(i, a, b) for(int i = (a); i <= (b); i ++ ) #define int long long usingnamespace std; constint N = 100010; int n; int a[N]; int tr[N * 2]; int ans[N];
intlowbit(int x) { return x & -x; }
voidadd(int x, int c) { for(int i = x; i < N; i += lowbit(i)) tr[i] += c; }
intquery(int x) { int res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; }
for(int i = n; i > 0; i -- ) { int rk = a[i] + 1; int l = 1, r = n; while(l < r) { int mid = l + r >> 1; if(query(mid) >= rk) r = mid; else l = mid + 1; } add(l, -1); ans[i] = l; }
#include<iostream> #define rep(i, a, b) for(int i = (a); i <= (b); i ++ ) usingnamespace std; constint N = 100010; int n, m; int a[N]; structnode { int l, r; int sum; }tr[N * 4];